// Copyright (c) 2019 Presto Labs Pte. Ltd.
// Author: donggu

#pragma once

#include <map>
#include <memory>
#include <string>
#include <tuple>
#include <utility>
#include <vector>

#include "coin2/base/config/app_config.h"
#include "coin2/exchange/base/executor/archive_executor.h"
#include "coin2/exchange/base/executor/live_executor.h"
#include "coin2/exchange/base/feed/system.h"
#include "coin2/exchange/base/market/market_exchange_api.h"
#include "coin2/exchange/base/symbology/product.h"
#include "coin2/exchange/di/constant.h"
#include "coin2/exchange/base/feed/counter/counter.h"

namespace coin2::feed::mgr {
namespace impl {

using namespace coin::proto;
using coin2::exchange::base::executor::ArchiveSyncExecutor;
using coin2::exchange::base::executor::LiveAsyncExecutor;
using coin2::exchange::base::feed::IFeedSubsystem;
using coin2::exchange::base::feed::IFeedSubscriber;
using coin2::exchange::base::symbology::IProduct;
using coin2::exchange::feed::ArchiveConfig_ArchiveType;
using coin2::exchange::feed::FeedManagerConfig;
using coin2::exchange::feed::FeedSystemType;
using coin2::exchange::base::feed::counter::FeedCounter;

class FeedSubsystemManager {
 public:
  explicit FeedSubsystemManager(
      const coin2::exchange::di::ConstantInjection& ci,
      const FeedManagerConfig& config,
      LiveAsyncExecutor* lass,
      ArchiveSyncExecutor* aass,
      exchange::base::feed::IFeedSubscriber* strategy);
  virtual ~FeedSubsystemManager();

  std::vector<IFeedSubsystem*> GetAllFeedSubsystems();

  std::vector<IProduct*> GetProducts() const;

  bool HasLass() const { return lass_ != nullptr; }
  bool HasAass() const { return aass_ != nullptr; }

  void DebugPrint() const;

  void GetHealthReport(int indent, std::string* report) const;

  bool HasLive() const {
    for (auto ftype : feed_system_types_) {
      if (ftype != FeedSystemType::FEED_SYSTEM_TYPE_ARCHIVE) {
        return true;
      }
    }
    return false;
  }

  const FeedCounter* GetCounter() const {
    return feed_counter_.get();
  }

 private:
  IFeedSubscriber* InitTimerManager(
    const FeedManagerConfig& config,
    IFeedSubscriber* strategy,
    boost::asio::io_context& main_ioc);

  void InitCounter(const FeedManagerConfig& config);

  std::vector<FeedSystemType> feed_system_types_;
  const FeedManagerConfig config_;
  LiveAsyncExecutor* lass_;
  ArchiveSyncExecutor* aass_;
  std::vector<std::unique_ptr<IFeedSubsystem>> systems_;
  std::unique_ptr<FeedCounter> feed_counter_;
};

}  // namespace impl

using impl::FeedSubsystemManager;

}  // namespace coin2::feed::mgr
